---
title: Convert a source document to PDF
summary: Dispatch a conversion request to the converter matching the source file extension.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-09-17
library: PdfAPI.SyncFusionCore
reference_type: package
operation_id: OP-SFC-001
trigger: Caller request (SyncfusionPdfService.Convert)
---

# Convert a source document to PDF

This is the single entry point for format conversion in this library: it validates the request, normalizes the file extension, and dispatches to the converter that matches it, before returning a uniform `PdfResult`.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-SFC-001 |
| **Trigger** | Caller request — `SyncfusionPdfService.Convert(request)` (`PdfAPI\Services\Syncfusion\SyncfusionPdfService.cs:82`) |
| **Inputs** | `ConvertRequest` (`File` bytes, `FileExtension`, `Options`/`Format`, `SourceSystemId`) |
| **Outputs** | `PdfResult` (`Document`, `Status`, `Message`, `Elapsed`, `OutputFormat`, `Extension`, `ImageId`, `PdfProcessorType = Syncfusion`) |
| **Primary components** | `ConverterFactory.Convert` |
| **Entry point** | `PdfApi.SyncFusionCore\Convert\ConverterFactory.cs` |

## Steps

1. Reject a null request by throwing `ArgumentNullException(nameof(request))` ([BR-SFC-001](../business-rules.md#br-sfc-001-null-conversion-request-rejected)).
2. Normalize `request.FileExtension` to lower case and trim leading/trailing `.` characters ([BR-SFC-002](../business-rules.md#br-sfc-002-case-insensitive-extension-normalization)).
3. Wrap `request.File` in a `MemoryStream` and switch on the normalized extension, constructing the matching converter and calling its `Convert(stream, request)` ([BR-SFC-003](../business-rules.md#br-sfc-003-extension-to-converter-mapping)):
   - `doc`/`docx` → [Word document to PDF](word-document-to-pdf.md)
   - `xls`/`xlsx` → [Excel workbook to PDF](excel-workbook-to-pdf.md)
   - `rtf` → [RTF document to PDF](rtf-document-to-pdf.md)
   - `txt` → [Plain text to PDF](plain-text-to-pdf.md)
   - `gif`/`jpg`/`jpeg`/`png` → [Raster image to PDF](raster-image-to-pdf.md)
   - `html` → [HTML to PDF](html-to-pdf.md)
   - `tif`/`tiff` → [TIFF to multi-page PDF](tiff-to-multi-page-pdf.md)
   - `pdf` → [PDF pass-through or PDF/A upgrade](pdf-passthrough-or-pdfa-upgrade.md)

   > **Origin**: Every branch delegates the actual byte-level conversion to [`Execute a single conversion (converter template)`](execute-single-conversion.md), which is implemented in this same library (`PdfAPI.SyncFusionCore`).
4. For the `txt` branch only: if the text conversion succeeded, recursively call `ConverterFactory.Convert` (this operation) with a new `ConvertRequest` whose `File` is the produced PDF, `FileExtension = "pdf"`, and the original `SourceSystemId` and `Options`; replace the result with the recursive result ([BR-SFC-004](../business-rules.md#br-sfc-004-text-converted-via-intermediate-pdf)).
   - This resubmission routes back through step 3's `pdf` branch, so [PDF pass-through or PDF/A upgrade](pdf-passthrough-or-pdfa-upgrade.md) applies PDF/A conformance uniformly regardless of source format.
5. For an unmatched extension, build `new PdfResult(SourceConversionType.Unknown, request)` with `Message = "Unsuppported extension ({ext})"`; no exception is thrown and `Status` stays at its default ([BR-SFC-005](../business-rules.md#br-sfc-005-unsupported-extension-reported-not-thrown)).
6. Set `result.Extension` to the normalized extension and return the result. The `MemoryStream` is disposed by the enclosing `using`, and the converter also disposes it through `BaseConverter`'s `using (stream)`.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([ConvertRequest received]) --> Null{"Request null?"}
	Null -->|Yes| ThrowErr([ArgumentNullException])
	Null -->|No| Norm["Normalize file extension<br>lower-case, trim dots"]
	Norm --> Dispatch{"Extension<br>matches a converter?"}
	Dispatch -->|"doc/docx/xls/xlsx/rtf/<br>image/html/tif/pdf"| RunConv["Run BaseConverter template<br>via matching converter"]
	Dispatch -->|txt| RunText["Run TxtConverter via<br>BaseConverter template"]
	Dispatch -->|No match| Unknown(["Return Unknown result<br>no exception thrown"])
	RunText --> TextOk{"Text conversion<br>succeeded?"}
	TextOk -->|Yes| Recurse["Recursively convert produced<br>PDF via pdf branch"]
	TextOk -->|No| ReturnFailed([Return failed PdfResult])
	Recurse --> RunConv
	RunConv --> SetExt["Stamp normalized extension<br>on result"]
	SetExt --> Result([Return PdfResult])
```

## Failure and edge-case behavior

- A null request throws immediately; no other step executes.
- An unsupported extension never throws — it returns a non-throwing `PdfResult` with `Status` left
  at its default rather than `Failed`.
- Any exception inside the delegated converter is captured by
  [`Execute a single conversion (converter template)`](execute-single-conversion.md) and turned into a failed `PdfResult`, not propagated to this operation's caller.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

## Sources
- `PdfApi.SyncFusionCore\Convert\ConverterFactory.cs`
- `PdfAPI\Services\Syncfusion\SyncfusionPdfService.cs`
